/*
 * Copyright (C) 2019-2020 Alibaba Group Holding Limited
 */

#include <stdbool.h>
#include <aos/log.h>
#include <aos/aos.h>
#include <devices/console_uart.h>
#include <devices/drv_snd_pangu.h>
#include <devices/devicelist.h>
#include <drv/gpio.h>
#include <sys_freq.h>
#include <yoc/partition.h>

#include "board_config.h"

#define TAG "INIT"

#define reg_wr(reg_addr) *((volatile uint32_t *)reg_addr)
extern void mdelay(uint32_t ms);

void cpu1_init(void)
{
    partition_t p = partition_open("cpu1");
    partition_info_t *info = hal_flash_get_info(p);
    LOGD(TAG, "cpu1->start_addr=0x%x", info->start_addr);
    LOGD(TAG, "cpu1->length=0x%x", info->length);
    LOGD(TAG, "cpu1 load_addr=0x%x", info->load_addr);
    if (info->load_addr == ~0) {
        LOGE(TAG, "cpu1 load addr error!");
        return;
    }
    partition_read(p, 0, (void *)info->load_addr, info->length);
    partition_close(p);

    // FIXME:
    reg_wr(0x30000080) = info->load_addr;
    reg_wr(0x30000008) &= ~0x1;
    reg_wr(0x30000008) |= 0x1;
    mdelay(200);
}

void cpu2_init(void)
{
    partition_t p = partition_open("cpu2");
    partition_info_t *info = hal_flash_get_info(p);
    LOGD(TAG, "cpu2->start_addr=0x%x", info->start_addr);
    LOGD(TAG, "cpu2->length=0x%x", info->length);
    LOGD(TAG, "cpu2 load_addr=0x%x", info->load_addr);
    if (info->load_addr == ~0) {
        LOGE(TAG, "cpu2 load addr error!");
        return;
    }
    partition_read(p, 0, (void *)info->load_addr, info->length);
    partition_close(p);
    reg_wr(0x30000044) = info->load_addr;
    reg_wr(0x30000008) &= ~0x02;
    reg_wr(0x30000008) |= 0x02;
    mdelay(200);
}

static void itcm_code_load()
{
extern int __data_end__;
extern int __itcm_code_start__;
extern int __itcm_code_end__;
uint32_t len = &__itcm_code_end__ - &__itcm_code_start__;
    memset((void *)(&__itcm_code_start__), 0, 0x7FFF);
    memcpy((void *)(&__itcm_code_start__), \
        (uint8_t *)(&__data_end__), \
        len * 4);
}

void board_base_init(void)
{
    itcm_code_load();
    uart_csky_register(0);
    uart_csky_register(1);

    spiflash_csky_register(0);
    iic_csky_register(0);

    console_init(CONSOLE_IDX, 115200, 512);

    /* load partition */
    int ret = partition_init();
    if (ret <= 0) {
        LOGE(TAG, "partition init failed");
    } else {
        cpu1_init();
        // cpu2_dnn_init();
        cpu2_init();

        LOGI(TAG, "find %d partitions", ret);
    }

    /* RTC CLK setting */
    extern void drv_lclk_select_src(clk_src_e);
    /* 设置内部RC晶振，用于RTC时钟 */
    drv_lclk_select_src(ELS_CLK);
    drv_set_rtc_freq(CONFIG_RTC_CLK);
}

void board_audio_init()
{
    int id_list[5] = {0, 1, AUDIO_REF_ADC_ID, EMPTY_INPUT_CHANNEL, EMPTY_INPUT_CHANNEL};
    snd_pangu_config_t config = {id_list, sizeof(id_list) / sizeof(int)};
    config.dac_db_max = -15;
    config.dac_db_min = -45;

    snd_card_pangu_register(&config);
}
